//@version=5
indicator("Premium Liquidity Hunter Algo ", overlay=true, max_boxes_count=500, max_lines_count=500, max_labels_count = 500)

// Inputs
swingSizeR       = input.int(10, 'Bars Right-Left', inline='brl')
swingSizeL       = input.int(15, '-', inline='brl')
showBoxes        = input.bool(true, 'Show Boxes ', inline='aa')
showSwingLines   = input.bool(true, 'Show Lines', inline='aa')
showBubbles      = input.bool(true, 'Show Labels ', inline='bb')
showVol          = input.bool(false, 'Show Volume', inline='bb')
showOId          = input.bool(false, 'Show OI ?   ', inline='cc')
extendtilfilled  = input.bool(true, 'Extend Until Fill', inline='cc')

// Conditions
hidefilled       = input.bool(false, 'Hide Filled', group='Conditions')
voltresh = input.int(0, 'Volume >', group='Conditions')
oitresh  = input.int(0, 'OI ? (abs.) >',  group='Conditions')
pnoid   = input.string('/', 'Only Swings With', options = ['Positive OI Delta', 'Negative OI Delta', '/'], group='Conditions')
// Appearance inputs
showhighs        = input.bool(true, '', inline='sh', group='Appearance')
showlows         = input.bool(true, '', inline='sl', group='Appearance')
sellcol          = input.color(#aa2430, 'Lows (Line - Label - Box)', inline = 'sh', group='Appearance')
buycol           = input.color(#66bb6a, 'Highs (Line - Label - Box)', inline='sl', group='Appearance')
sellcolB         = input.color(#aa2430, '', inline='sh', group='Appearance')
buycolB          = input.color(#66bb6a, '', inline = 'sl', group='Appearance')
sellboxCol       = input.color(#80192231, '', inline = 'sh', group='Appearance')
buyboxCol        = input.color(#66bb6a31, '', inline='sl', group='Appearance')
lineStyle        = input.string('Dotted', 'Line Style + Width', ['Solid', 'Dashed', 'Dotted'], inline='l', group='Appearance')
lineWid          = input.int(1, '', inline='l', group='Appearance')
boxWid           = input.float(0.7, 'Box Width + Type ', step=0.1, inline='xx', group='Appearance')
boxStyle         = input.string('TYPE 1', '', options=['TYPE 1', 'TYPE 2'], inline='xx', group='Appearance')
labelsize        = input.string('Size: Tiny', 'Text Style        ', options = ['Size: Normal','Size: Large', 'Size: Small', 'Size: Tiny', 'Size: Auto' ], inline='txt', group = 'Appearance' )
texthalign       = input.string('Right','', options = ['Middle', 'Right', 'Left'], inline='txt', group = 'Appearance')
lookback         = input.bool(false, '', inline='lb')
daysBack         = input.float(150, 'Lookback (D)               ',inline='lb')
// OI Data
binance   = input.bool(true, 'Binance USDT.P', inline = 'src',  group = 'Open Interest')
binance2  = input.bool(true, 'Binance USD.P',  inline = 'src',  group = 'Open Interest')
binance3  = input.bool(true, 'Binance BUSD.P', inline = 'src2', group = 'Open Interest')
bitmex    = input.bool(true, 'BitMEX USD.P',   inline = 'src2', group = 'Open Interest')
bitmex2   = input.bool(true, 'BitMEX USDT.P ', inline = 'src3', group = 'Open Interest')
kraken    = input.bool(true, 'Kraken USD.P',   inline = 'src3', group = 'Open Interest')

// Calculating inRange, used for lookback in days
MSPD             = 24 * 60 * 60 * 1000
lastBarDate      = timestamp(year(timenow), month(timenow), dayofmonth(timenow), hour(timenow), minute(timenow), second(timenow))
thisBarDate      = timestamp(year, month, dayofmonth, hour, minute, second)
daysLeft         = math.abs(math.floor((lastBarDate - thisBarDate) / MSPD))
inRange          = lookback ? (daysLeft < daysBack) : true

//Pivot calculations
int prevHighIndex= na, int prevLowIndex= na, bool highActive= false, bool lowActive= false, bool h= false, bool l= false
pivHi            = ta.pivothigh(high, swingSizeL, swingSizeR)
pivLo            = ta.pivotlow(low, swingSizeL, swingSizeR)

if not na(pivHi)
    h := true
    prevHighIndex := bar_index - swingSizeR
if not na(pivLo)
    l := true
    prevLowIndex  := bar_index - swingSizeR

// Getting OI data
mex =  syminfo.basecurrency=='BTC' ? 'XBT' : string(syminfo.basecurrency)
oid1 = nz(request.security('BINANCE' + ":" + string(syminfo.basecurrency) + 'USDT.P_OI',  timeframe.period,  close-close[1], ignore_invalid_symbol = true), 0)
oid2 = nz(request.security('BINANCE' + ":" + string(syminfo.basecurrency) + 'USD.P_OI',   timeframe.period,  close-close[1], ignore_invalid_symbol = true), 0)
oid3 = nz(request.security('BINANCE' + ":" + string(syminfo.basecurrency) + 'BUSD.P_OI',  timeframe.period,  close-close[1], ignore_invalid_symbol = true), 0)
oid4 = nz(request.security('BITMEX'  + ":" + mex                          + 'USD.P_OI',   timeframe.period,  close-close[1], ignore_invalid_symbol = true), 0)
oid5 = nz(request.security('BITMEX'  + ":" + mex                          + 'USDT.P_OI',  timeframe.period,  close-close[1], ignore_invalid_symbol = true), 0)
oid6 = nz(request.security('KRAKEN'  + ":" + string(syminfo.basecurrency) + 'USD.P_OI',   timeframe.period,  close-close[1], ignore_invalid_symbol = true), 0)

deltaOI   = (binance ? nz(oid1,0) : 0)   +   (binance2 ? nz(oid2,0)/close : 0)   +    (binance3 ? nz(oid3,0) : 0)    +   (bitmex ? nz(oid4,0)/close : 0)   +   (bitmex2 ? nz(oid5,0)/close : 0)   +   (kraken ? nz(oid6,0)/close : 0)




//Volume, OI, box width
vol         = volume[swingSizeR]

oitreshcond = oitresh > 0 ? math.abs(deltaOI[swingSizeR])>oitresh : true
voltreshcond = voltresh > 0 ? vol > voltresh : true
oicond = pnoid=='Positive OI Delta' ? deltaOI[swingSizeR]>0 : pnoid=='Negative OI Delta' ? deltaOI[swingSizeR]<0 : true

color CLEAR = color.rgb(0,0,0,100)
boxWid1     = 0.001 * boxWid


// Styles
boxStyle(x) =>
    switch x
        'TYPE 1' => h ? pivHi : l ? pivLo : na
        'TYPE 2' => h ? pivHi * (1 - boxWid1) : l ? pivLo * (1 + boxWid1) : na
lineStyle(x) =>
    switch x
        'Solid'  => line.style_solid
        'Dashed' => line.style_dashed
        'Dotted' => line.style_dotted
switchtextsize(textsize) =>
    switch textsize
        'Size: Normal'  => size.normal
        'Size: Small'   => size.small
        'Size: Tiny'    => size.tiny
        'Size: Auto'    => size.auto
        'Size: Large'   => size.large
switchhalign(texthalign) =>
    switch texthalign
        'Middle'        => text.align_center
        'Right'         => text.align_right
        'Left'          => text.align_left

//Swing level labels
var levelBoxes = array.new_box(), var levelLines = array.new_line()
if h and inRange and showhighs and oitreshcond and voltreshcond and oicond
    hBox    = box.new(prevHighIndex, pivHi * (1 + boxWid1), bar_index, boxStyle(boxStyle), border_color = na, bgcolor = showBoxes ? sellboxCol : CLEAR, text= (showVol ? str.tostring(vol, format.volume) : na) +' '+ (showOId ? str.tostring(deltaOI[swingSizeR], format.volume) : ''),text_halign=switchhalign(texthalign),text_valign=text.align_center,text_color=chart.fg_color, text_size=switchtextsize(labelsize))
    hLine   = line.new(prevHighIndex, pivHi, bar_index, pivHi, color = showSwingLines ? sellcol : CLEAR, style=lineStyle(lineStyle), width=lineWid)
    array.push(levelBoxes, hBox)
    array.push(levelLines, hLine)
if l and inRange and showhighs and oitreshcond and voltreshcond and oicond
    lBox    = box.new(prevLowIndex, pivLo * (1 - boxWid1), bar_index, boxStyle(boxStyle), border_color = na, bgcolor = showBoxes ? buyboxCol : CLEAR, text= (showVol ? str.tostring(vol, format.volume) : na) +' '+ (showOId ? str.tostring(deltaOI[swingSizeR], format.volume) : ''),text_halign=switchhalign(texthalign),text_valign=text.align_center,text_color=chart.fg_color, text_size=switchtextsize(labelsize))
    lLine   = line.new(prevLowIndex, pivLo, bar_index, pivLo, color = showSwingLines ? buycol : CLEAR, style=lineStyle(lineStyle), width=lineWid)
    array.push(levelBoxes, lBox)
    array.push(levelLines, lLine)

// Looping over the full array of lines and updating them, and deleting them if they have been touched
size = array.size(levelBoxes)
if size > 0
    for i = 0 to size - 1
        j = size - 1 - i
        box = array.get(levelBoxes, j)
        line = array.get(levelLines, j)
        level = line.get_y2(line)
        filled = (high >= level and low <= level)

        if filled and extendtilfilled and not hidefilled
            array.remove(levelLines, j)
            array.remove(levelBoxes, j)
            continue 

        box.set_right(box, bar_index+1)
        line.set_x2(line, bar_index+1)
        if filled and hidefilled
            array.remove(levelLines, j)
            array.remove(levelBoxes, j)
            line.delete(line)
            box.delete(box)

        if not filled and not extendtilfilled
            array.remove(levelLines, j)
            array.remove(levelBoxes, j)
            continue 
            box.set_right(box, bar_index[0]+4)
            line.set_x2(line, bar_index[0]+4)


// Deleting the oldest lines if array is too big 
if array.size(levelBoxes) >= 500
    int i = 0
    while array.size(levelBoxes) >= 500
        box = array.get(levelBoxes, i)
        line = array.get(levelLines, i)
        box.delete(box)
        line.delete(line)
        array.remove(levelBoxes, i)
        array.remove(levelLines, i)
        i += 1 
        
// Plotting circle labels
plotshape(showhighs and showBubbles and h and oitreshcond and voltreshcond and oicond ? high[swingSizeR] : na, style=shape.circle, location = location.absolute, offset = -swingSizeR, color=sellcolB, size = size.tiny)
plotshape(showlows and showBubbles and l and oitreshcond and voltreshcond and oicond ? low[swingSizeR] : na, style=shape.circle, location = location.absolute, offset = -swingSizeR, color=buycolB, size = size.tiny)

//////////////////////////////////////////////////////////////////////-------------------/////////////////////////////////////////////////

//Option to show Liquidity lines on the chart
show_liquidity = input(true,"Show Liquidity? (Daily, Weekly, Monthly)",inline='Show Liquidity'
 , group = 'Configuration')

var gStartOffset = 0
var gEndOffset  = 25

color_text_prev_high_low = input.color(color.new(#f6eb54, 13), 'Color of previous day high and low'
  , group = 'Configuration')

english_language_selected = input(true, 'Show Labels in English'
  , group = 'Configuration')



// DEFINE COLORS of the lines displayed on the chart
// --> Blue lines: Daily liquidity
// --> Yellow lines: Weekly Liquidity
// --> Purple lines: Monthly liquidity
//daily liquidity
gIsDailyEnabled  = true
gDailyAboveLiquidityColor = color.new(#4987d3, 13)
gDailyBelowLiquidityColor = color.new(#4987d3, 13)
gDailyWidth = 1 

//weekly liquidity
gIsWeeklyEnabled = true
gWeeklyAboveLiquidityColor = color.new(#f6eb54, 13)
gWeeklyBelowLiquidityColor = color.new(#f6eb54, 13)
gWeeklyWidth  = 1

//month liquidity
gIsMonthlyEnabled              = true
gMonthlyAboveLiquidityColor    = color.new(#f66ecf, 13)
gMonthlyBelowLiquidityColor    = color.new(#f66ecf, 13)
gMonthlyWidth                  = 1

cleanedLevelColor              = color.new(#ffffff, 100)
cleanedLevelStyle              = "Dashed"


var highArray                  = array.new_float()
var lowArray                   = array.new_float()
var highLinesArray             = array.new_line()
var lowLinesArray              = array.new_line()
var purgedLinesArray           = array.new_line()

[prevDayHigh, prevDayLow]       = request.security(syminfo.tickerid, "D",   [high[1], low[1]], lookahead=barmerge.lookahead_on)
[prevWeekHigh, prevWeekLow]     = request.security(syminfo.tickerid, "W",   [high[1], low[1]], lookahead=barmerge.lookahead_on)
[prevMonthHigh, prevMonthLow]   = request.security(syminfo.tickerid, "M",   [high[1], low[1]], lookahead=barmerge.lookahead_on)
[prev4HHigh, prev4HLow]         = request.security(syminfo.tickerid, "240", [high[1], low[1]], lookahead=barmerge.lookahead_on)
[prev1HHigh, prev1HLow]         = request.security(syminfo.tickerid, "60",  [high[1], low[1]], lookahead=barmerge.lookahead_on)


//Set Labels text according language selected (English or Portuguese)
demand_lbl_txt = ""
if (english_language_selected == false)
    demand_lbl_txt := "Zona de Compra"
else
    demand_lbl_txt := "Demand/Buy Zone"    

supply_lbl_txt = ""
if (english_language_selected == false)
    supply_lbl_txt := "Zona de Venda"
else
    supply_lbl_txt := "Supply/Sell Zone"

strong_high_lbl = ""
if (english_language_selected == false)
    strong_high_lbl := "Alto Forte"
else
    strong_high_lbl := "Strong High"

strong_low_lbl = ""
if (english_language_selected == false)
    strong_low_lbl := "Baixo Forte"
else
    strong_low_lbl := "Strong Low"


weak_low_lbl = ""
if (english_language_selected == false)
    weak_low_lbl := "Baixo Fraco"
else
    weak_low_lbl := "Weak Low"

weak_high_lbl = ""
if (english_language_selected == false)
    weak_high_lbl := "Alto Fraco"
else
    weak_high_lbl := "Weak High"

previous_day_high_lbl = ""
if (english_language_selected == false)
    previous_day_high_lbl := "Preo Mximo do dia Anterior"
else
    previous_day_high_lbl := "Previous Day Highest Price"

previous_day_low_lbl = ""
if (english_language_selected == false)
    previous_day_low_lbl := "Preo Minimo do dia Anterior"
else
    previous_day_low_lbl := "Previous Day Lowest Price"

//       Functions 
f_drawLine(_y, _c, _w=1) => line.new(bar_index, _y, bar_index, _y, color=_c, width=_w)

f_create(_high, _low, _upperColor, _lowerColor, _linewidth) =>
    array.push(highArray, _high)
    array.push(lowArray, _low)
    array.push(highLinesArray, f_drawLine(_high, _upperColor, _linewidth))
    array.push(lowLinesArray, f_drawLine(_low, _lowerColor, _linewidth))

f_updateStickyLevels(_levels) =>
    for _line in _levels
        line.set_x1(_line, bar_index + gStartOffset)
        line.set_x2(_line, bar_index + gEndOffset)

f_moveLevel(_from, _to, _level, _index) =>
    array.push(_to, _level)
    array.remove(_from, _index)

f_highlightPurgedLevel(_level) =>
    _style = cleanedLevelStyle == "Solid" ? line.style_solid : cleanedLevelStyle == "Dashed" ? line.style_dashed : line.style_dotted
    line.set_color(_level, cleanedLevelColor)
    line.set_style(_level, _style)

f_updateUpperLevels(_high, _highs, _levels, _purgedLevels) =>
    while array.min(_highs) < _high
        for [_index, _value] in _highs
            if _high > _value
                _line = array.get(_levels, _index)
                f_highlightPurgedLevel(_line)
                f_moveLevel(_levels, _purgedLevels, _line, _index)
                array.remove(_highs, _index)
f_updateLowerLevels(_low, _lows, _levels, _purgedLevels) =>
    while array.max(_lows) > _low
        for [_index, _value] in _lows
            if _low < _value
                _line = array.get(_levels, _index)
                f_highlightPurgedLevel(_line)
                f_moveLevel(_levels, _purgedLevels, _line, _index)
                array.remove(_lows, _index)

f_clearLevels(_levels) =>
    while array.size(_levels) > 0
        for [_index, _line] in _levels
            line.delete(array.remove(_levels, _index))

f_isHigherTimeframe(_timeframe) => timeframe.in_seconds() <= timeframe.in_seconds(_timeframe)


//Draw Lines if  liquidity is enabled
if show_liquidity
    if gIsDailyEnabled and f_isHigherTimeframe("D") and ta.change(time("D"))
        f_create(prevDayHigh, prevDayLow, gDailyAboveLiquidityColor, gDailyBelowLiquidityColor, gDailyWidth)

    if gIsWeeklyEnabled and f_isHigherTimeframe("W") and ta.change(time("W"))
        f_create(prevWeekHigh, prevWeekLow, gWeeklyAboveLiquidityColor, gWeeklyBelowLiquidityColor, gWeeklyWidth)

    if gIsMonthlyEnabled and f_isHigherTimeframe("M") and ta.change(time("M"))
        f_create(prevMonthHigh, prevMonthLow, gMonthlyAboveLiquidityColor, gMonthlyBelowLiquidityColor, gMonthlyWidth)


if barstate.islast
    f_updateStickyLevels(highLinesArray)
    f_updateStickyLevels(lowLinesArray)
    f_updateStickyLevels(purgedLinesArray)

// Highlight the levels that got their liquidity taken

f_updateUpperLevels(high, highArray, highLinesArray, purgedLinesArray)
f_updateLowerLevels(low, lowArray, lowLinesArray, purgedLinesArray)

// Clean the levels that had their liquidity taken on a daily basis
if ta.change(time("D"))
    f_clearLevels(purgedLinesArray)

color TRANSP_COLOR = #ffffff00

//Tooltips
string TOOLTIP          = 'Allows to display historical Structure'
string STYLE        = 'color theme'
string COLOR_CANDLES = 'Display additional candles'


mode = 'Historical'
style = 'Colored'
show_trend = false


//Internal Structure
show_internals = false
show_ibull =  'All'
swing_ibull_css =#5ef8d727


//Bear Structure
show_ibear = 'All'
swing_ibear_css = #c40d0d5b
ifilter_confluence = false


//Swing Structure
show_Structure = true

//Bull Structure
show_bull = 'All'
swing_bull_css = #0dea7f63

//Bear Structure
show_bear = 'All'
swing_bear_css =  #c40d0de8

//Swings
show_swings = true
length = 50
show_hl_swings = true


//Order Blocks Variables

show_iob = false
iob_showlast = 5
show_ob = true
ob_showlast = 5
ob_filter = 'Atr'
ibull_ob_css = #0bf6841f
ibear_ob_css = color.new(#e64444, 80)
bull_ob_css = #0bf6841f
bear_ob_css = color.new(#e64444, 80)


//Imbalances / Gaps

show_fvg = true
fvg_auto = true
fvg_tf = ''
bull_fvg_css = color.new(#b980ef4d, 70)
bear_fvg_css = color.new(#b980ef4d, 70)
fvg_extend = 5


//Previous day/week high/low

//Daily
show_pdhl = true
pdhl_style = ''
pdhl_css = #ffffff

//Premium and Discount zones

show_sd = true
premium_css = #e616169c
discount_css = #0899445d

//Functions
n = bar_index

atr = ta.atr(200)
cmean_range = ta.cum(high - low) / n

//HL Output function
hl() => [high, low]

//Get ohlc values function
get_ohlc()=> [close[1], open[1], high, low, high[2], low[2]]

//Display Structure function
display_Structure(x, y, txt, css, dashed, down, lbl_size)=>
    structure_line = line.new(x, y, n, y
      , color = css
      , style = dashed ? line.style_dashed : line.style_solid)

    structure_lbl = label.new(int(math.avg(x, n)), y, txt
      , color = TRANSP_COLOR
      , textcolor = css
      , style = down ? label.style_label_down : label.style_label_up
      , size = lbl_size)

    if mode == 'Present'
        line.delete(structure_line[1])
        label.delete(structure_lbl[1])

//Swings detection/measurements
swings_calc(len)=>
    var os = 0
    
    upper = ta.highest(len)
    lower = ta.lowest(len)

    os := high[len] > upper ? 0 : low[len] < lower ? 1 : os[1]

    top = os == 0 and os[1] != 0 ? high[len] : 0
    btm = os == 1 and os[1] != 1 ? low[len] : 0

    [top, btm]

//Order block coordinates function
ob_coord(use_max, loc, target_top, target_btm, target_left, target_type)=>
    min = 99999999.
    max = 0.
    idx = 1

    ob_threshold = ob_filter == 'Atr' ? atr : cmean_range 

    //Search for highest/lowest high within the structure interval and get range
    if use_max
        for i = 1 to (n - loc)-1
            if (high[i] - low[i]) < ob_threshold[i] * 2
                max := math.max(high[i], max)
                min := max == high[i] ? low[i] : min
                idx := max == high[i] ? i : idx
    else
        for i = 1 to (n - loc)-1
            if (high[i] - low[i]) < ob_threshold[i] * 2
                min := math.min(low[i], min)
                max := min == low[i] ? high[i] : max
                idx := min == low[i] ? i : idx

    array.unshift(target_top, max)
    array.unshift(target_btm, min)
    array.unshift(target_left, time[idx])
    array.unshift(target_type, use_max ? -1 : 1)

//Set order blocks
display_ob(boxes, target_top, target_btm, target_left, target_type, show_last, swing, size)=>
    for i = 0 to math.min(show_last-1, size-1)
        get_box = array.get(boxes, i)

        box.set_lefttop(get_box, array.get(target_left, i), array.get(target_top, i))
        box.set_rightbottom(get_box, array.get(target_left, i), array.get(target_btm, i))
        box.set_extend(get_box, extend.right)

        color css = na
        
        if swing 
            if style == 'Monochrome'
                css := array.get(target_type, i) == 1 ? color.new(#b2b5be, 80) : color.new(#5d606b, 80)
                border_css = array.get(target_type, i) == 1 ? #b2b5be : #5d606b
            else
                css := array.get(target_type, i) == 1 ? bull_ob_css : bear_ob_css
                

            box.set_border_color(get_box, css)
            box.set_bgcolor(get_box, css)
        else
            if style == 'Monochrome'
                css := array.get(target_type, i) == 1 ? color.new(#b2b5be, 80) : color.new(#5d606b, 80)
            else
                css := array.get(target_type, i) == 1 ? ibull_ob_css : ibear_ob_css
            
            box.set_border_color(get_box, css)
            box.set_bgcolor(get_box, css)
        
//Line Style function
get_line_style(style) =>
    out = switch style
        '???'  => line.style_solid
        '----' => line.style_dashed
        '' => line.style_dotted

//Set line and labels for previous high and lows
define_previous_days_prices(h, l, tf, css)=>
    var line high_line = line.new(na,na,na,na
      , xloc = xloc.bar_time
      , color = css
      , style = get_line_style(pdhl_style))

    var label high_lbl = label.new(na,na
      , xloc = xloc.bar_time
      , text = str.format(previous_day_high_lbl, tf)
      , color = TRANSP_COLOR
      , textcolor = color_text_prev_high_low
      , size = size.small
      , style = label.style_label_left)

    var line low_line = line.new(na,na,na,na
      , xloc = xloc.bar_time
      , color = css
      , style = get_line_style(pdhl_style))

    var label low_lbl = label.new(na,na
      , xloc = xloc.bar_time
      , text = str.format(previous_day_low_lbl, tf)
      , color = TRANSP_COLOR
      , textcolor = color_text_prev_high_low
      , size = size.small
      , style = label.style_label_left)

    hy = ta.valuewhen(h != h[1], h, 1)
    hx = ta.valuewhen(h == high, time, 1)

    ly = ta.valuewhen(l != l[1], l, 1)
    lx = ta.valuewhen(l == low, time, 1)

    if barstate.islast
        ext = time + (time - time[1])*20

        //High
        line.set_xy1(high_line, hx, hy)
        line.set_xy2(high_line, ext, hy)

        label.set_xy(high_lbl, ext, hy)

        //Low
        line.set_xy1(low_line, lx, ly)
        line.set_xy2(low_line, ext, ly)

        label.set_xy(low_lbl, ext, ly)

//-----------------------------------------------------------------------------}
//Global variables
//-----------------------------------------------------------------------------{
var trend = 0, var itrend = 0

var top_y = 0., var top_x = 0
var btm_y = 0., var btm_x = 0

var itop_y = 0., var itop_x = 0
var ibtm_y = 0., var ibtm_x = 0

var trail_up = high, var trail_dn = low
var trail_up_x = 0,  var trail_dn_x = 0

var top_cross = true,  var btm_cross = true
var itop_cross = true, var ibtm_cross = true

var txt_top = '',  var txt_btm = ''

//Alerts
bull_choch_alert = false 
bull_bos_alert   = false 

bear_choch_alert = false 
bear_bos_alert   = false 

bull_ichoch_alert = false 
bull_ibos_alert   = false 

bear_ichoch_alert = false 
bear_ibos_alert   = false 

bull_iob_break = false 
bear_iob_break = false

bull_ob_break = false 
bear_ob_break = false

eqh_alert = false 
eql_alert = false 

//Structure colors
var bull_css = style == 'Monochrome' ? #b2b5be 
  : swing_bull_css

var bear_css = style == 'Monochrome' ? #b2b5be 
  : swing_bear_css

var ibull_css = style == 'Monochrome' ? #b2b5be 
  : swing_ibull_css

var ibear_css = style == 'Monochrome' ? #b2b5be 
  : swing_ibear_css

//Swings
[top, btm] = swings_calc(length)

[itop, ibtm] = swings_calc(5)

//-----------------------------------------------------------------------------}
//Pivot High
//-----------------------------------------------------------------------------{
var line extend_top = na

var label extend_top_lbl = label.new(na, na
  , color = TRANSP_COLOR
  , textcolor = bear_css
  , style = label.style_label_down
  , size = size.small)

if top
    top_cross := true
    txt_top := top > top_y ? 'HH' : 'LH'

    if show_swings
        top_lbl = label.new(n-length, top, txt_top
          , color = TRANSP_COLOR
          , textcolor = bear_css
          , style = label.style_label_down
          , size = size.small)

        if mode == 'Present'
            label.delete(top_lbl[1])

    //Extend recent top to last bar
    line.delete(extend_top[1])
    extend_top := line.new(n-length, top, n, top
      , color = bear_css)

    top_y := top
    top_x := n - length

    trail_up := top
    trail_up_x := n - length

if itop
    itop_cross := true

    itop_y := itop
    itop_x := n - 5

//Trailing maximum
trail_up := math.max(high, trail_up)
trail_up_x := trail_up == high ? n : trail_up_x

//Set top extension label/line
if barstate.islast and show_hl_swings
    line.set_xy1(extend_top, trail_up_x, trail_up)
    line.set_xy2(extend_top, n + 20, trail_up)

    label.set_x(extend_top_lbl, n + 20)
    label.set_y(extend_top_lbl, trail_up)
    label.set_text(extend_top_lbl, trend < 0 ? strong_high_lbl : weak_high_lbl)

//-----------------------------------------------------------------------------}
//Pivot Low
//-----------------------------------------------------------------------------{
var line extend_btm = na 

var label extend_btm_lbl = label.new(na, na
  , color = TRANSP_COLOR
  , textcolor = bull_css
  , style = label.style_label_up
  , size = size.small)

if btm
    btm_cross := true
    txt_btm := btm < btm_y ? 'LL' : 'HL'
    
    if show_swings
        btm_lbl = label.new(n - length, btm, txt_btm
          , color = TRANSP_COLOR
          , textcolor = bull_css
          , style = label.style_label_up
          , size = size.small)

        if mode == 'Present'
            label.delete(btm_lbl[1])
    
    //Extend recent btm to last bar
    line.delete(extend_btm[1])
    extend_btm := line.new(n - length, btm, n, btm
      , color = bull_css)

    btm_y := btm
    btm_x := n-length

    trail_dn := btm
    trail_dn_x := n-length

if ibtm
    ibtm_cross := true

    ibtm_y := ibtm
    ibtm_x := n - 5

//Trailing minimum
trail_dn := math.min(low, trail_dn)
trail_dn_x := trail_dn == low ? n : trail_dn_x

//Set btm extension label/line
if barstate.islast and show_hl_swings
    line.set_xy1(extend_btm, trail_dn_x, trail_dn)
    line.set_xy2(extend_btm, n + 20, trail_dn)

    label.set_x(extend_btm_lbl, n + 20)
    label.set_y(extend_btm_lbl, trail_dn)
    label.set_text(extend_btm_lbl, trend > 0 ? strong_low_lbl : weak_low_lbl)

//-----------------------------------------------------------------------------}
//Order Blocks Arrays
//-----------------------------------------------------------------------------{
var iob_top = array.new_float(0)
var iob_btm = array.new_float(0)
var iob_left = array.new_int(0)
var iob_type = array.new_int(0)

var ob_top = array.new_float(0)
var ob_btm = array.new_float(0)
var ob_left = array.new_int(0)
var ob_type = array.new_int(0)

//-----------------------------------------------------------------------------}
//Pivot High BOS and Choch
//-----------------------------------------------------------------------------{
//Filtering
var bull_concordant = true

if ifilter_confluence
    bull_concordant := high - math.max(close, open) > math.min(close, open - low)

//Detect internal bullish Structure
if ta.crossover(close, itop_y) and itop_cross and top_y != itop_y and bull_concordant
    bool choch = na
    
    if itrend < 0
        choch := true
        bull_ichoch_alert := true
    else 
        bull_ibos_alert := true
    
    txt = ""
    if(english_language_selected == false)
        txt := choch ? 'Alterao de Carter' : 'Quebra Estrutura'
    else
        txt := choch ? 'Change of Character' : 'Break of Structure'    

    if show_internals
        if show_ibull == 'All' or (show_ibull == 'BOS' and not choch) or (show_ibull == 'CHoCH' and choch)
            display_Structure(itop_x, itop_y, txt, ibull_css, true, true, size.tiny)
    
    itop_cross := false
    itrend := 1
    
    //Internal Order Block
    if show_iob
        ob_coord(false, itop_x, iob_top, iob_btm, iob_left, iob_type)

//Detect bullish Structure
if ta.crossover(close, top_y) and top_cross
    bool choch = na
    
    if trend < 0
        choch := true
        bull_choch_alert := true
    else 
        bull_bos_alert := true

    txt = ""
    if(english_language_selected == false)
        txt := choch ? 'Alterao de Carter' : 'Quebra Estrutura'
    else
        txt := choch ? 'Change of Character' : 'Break of Structure'    
    //txt = choch ? 'Alterao de Carter' : 'Quebra Estrutura'
    
    if show_Structure
        if show_bull == 'All' or (show_bull == 'BOS' and not choch) or (show_bull == 'CHoCH' and choch)
            display_Structure(top_x, top_y, txt, #0ddc67d0, true, true, size.small)
    
    //Order Block
    if show_ob
        ob_coord(false, top_x, ob_top, ob_btm, ob_left, ob_type)

    top_cross := false
    trend := 1

//-----------------------------------------------------------------------------}
//Pivot Low BOS and CHoCH
//-----------------------------------------------------------------------------{
var bear_concordant = true

if ifilter_confluence
    bear_concordant := high - math.max(close, open) < math.min(close, open - low)

//Detect internal bearish Structure
if ta.crossunder(close, ibtm_y) and ibtm_cross and btm_y != ibtm_y and bear_concordant
    bool choch = false
    
    if itrend > 0
        choch := true
        bear_ichoch_alert := true
    else 
        bear_ibos_alert := true
    
    txt = ""
    if(english_language_selected == false)
        txt := choch ? 'Alterao de Carter' : 'Quebra Estrutura'
    else
        txt := choch ? 'Change of Character' : 'Break of Structure'    
    //txt = choch ? 'Alterao de Carter' : 'QUEBRA DE ESTRUTURA'

    if show_internals
        if show_ibear == 'All' or (show_ibear == 'BOS' and not choch) or (show_ibear == 'CHoCH' and choch)
            display_Structure(ibtm_x, ibtm_y, txt, ibear_css, true, false, size.small)
    
    ibtm_cross := false
    itrend := -1
    
    //Internal Order Block
    if show_iob
        ob_coord(true, ibtm_x, iob_top, iob_btm, iob_left, iob_type)

//Detect bearish Structure
if ta.crossunder(close, btm_y) and btm_cross
    bool choch = na
    
    if trend > 0
        choch := true
        bear_choch_alert := true
    else 
        bear_bos_alert := true

    txt = ""
    if(english_language_selected == false)
        txt := choch ? 'Alterao de Carter' : 'Quebra Estrutura'
    else
        txt := choch ? 'Change of Character' : 'Break of Structure'    
    
    //txt = choch ? 'Alterao de Carter' : 'QUEBRA DE ESTRUTURA'
    
    if show_Structure
        if show_bear == 'All' or (show_bear == 'BOS' and not choch) or (show_bear == 'CHoCH' and choch)
            display_Structure(btm_x, btm_y, txt, #dc0d0dd0, true, false, size.small)
    
    //Order Block
    if show_ob
        ob_coord(true, btm_x, ob_top, ob_btm, ob_left, ob_type)

    btm_cross := false
    trend := -1

//-----------------------------------------------------------------------------}
//Order Blocks
//-----------------------------------------------------------------------------{
//Set order blocks
var iob_boxes = array.new_box(0)
var ob_boxes = array.new_box(0)

//Delete internal order blocks box coordinates if top/bottom is broken
for element in iob_type
    index = array.indexof(iob_type, element)

    if close < array.get(iob_btm, index) and element == 1
        array.remove(iob_top, index) 
        array.remove(iob_btm, index) 
        array.remove(iob_left, index) 
        array.remove(iob_type, index)
        bull_iob_break := true

    else if close > array.get(iob_top, index) and element == -1
        array.remove(iob_top, index) 
        array.remove(iob_btm, index)
        array.remove(iob_left, index) 
        array.remove(iob_type, index)
        bear_iob_break := true

//Delete internal order blocks box coordinates if top/bottom is broken
for element in ob_type
    index = array.indexof(ob_type, element)

    if close < array.get(ob_btm, index) and element == 1
        array.remove(ob_top, index) 
        array.remove(ob_btm, index) 
        array.remove(ob_left, index) 
        array.remove(ob_type, index)
        bull_ob_break := true

    else if close > array.get(ob_top, index) and element == -1
        array.remove(ob_top, index) 
        array.remove(ob_btm, index)
        array.remove(ob_left, index) 
        array.remove(ob_type, index)
        bear_ob_break := true

iob_size = array.size(iob_type)
ob_size = array.size(ob_type)

if barstate.isfirst
    if show_iob
        for i = 0 to iob_showlast-1
            array.push(iob_boxes, box.new(na,na,na,na, xloc = xloc.bar_time))
    if show_ob
        for i = 0 to ob_showlast-1
            array.push(ob_boxes, box.new(na,na,na,na, xloc = xloc.bar_time))

if iob_size > 0
    if barstate.islast
        display_ob(iob_boxes, iob_top, iob_btm, iob_left, iob_type, iob_showlast, false, iob_size)

if ob_size > 0
    if barstate.islast
        display_ob(ob_boxes, ob_top, ob_btm, ob_left, ob_type, ob_showlast, true, ob_size)


//-----------------------------------------------------------------------------}
//Imbalances
//-----------------------------------------------------------------------------{
var bullish_fvg_max = array.new_box(0)
var bullish_fvg_min = array.new_box(0)

var bearish_fvg_max = array.new_box(0)
var bearish_fvg_min = array.new_box(0)

float bullish_fvg_avg = na
float bearish_fvg_avg = na

bullish_fvg_cnd = false
bearish_fvg_cnd = false

[src_c1, src_o1, src_h, src_l, src_h2, src_l2] =
  request.security(syminfo.tickerid, fvg_tf, get_ohlc())

if show_fvg
    delta_per = (src_c1 - src_o1) / src_o1 * 100

    change_tf = timeframe.change(fvg_tf)

    threshold = fvg_auto ? ta.cum(math.abs(change_tf ? delta_per : 0)) / n * 2 
      : 0

    //FVG conditions
    bullish_fvg_cnd := src_l > src_h2
      and src_c1 > src_h2 
      and delta_per > threshold
      and change_tf

    bearish_fvg_cnd := src_h < src_l2 
      and src_c1 < src_l2 
      and -delta_per > threshold
      and change_tf

    //FVG Areas
    if bullish_fvg_cnd
        array.unshift(bullish_fvg_max, box.new(n-1, src_l, n + fvg_extend, math.avg(src_l, src_h2)
          , border_color = bull_fvg_css
          , bgcolor = bull_fvg_css))
        
        array.unshift(bullish_fvg_min, box.new(n-1, math.avg(src_l, src_h2), n + fvg_extend, src_h2
          , border_color = bull_fvg_css
          , bgcolor = bull_fvg_css))
    
    if bearish_fvg_cnd
        array.unshift(bearish_fvg_max, box.new(n-1, src_h, n + fvg_extend, math.avg(src_h, src_l2)
          , border_color = bear_fvg_css
          , bgcolor = bear_fvg_css))
        
        array.unshift(bearish_fvg_min, box.new(n-1, math.avg(src_h, src_l2), n + fvg_extend, src_l2
          , border_color = bear_fvg_css
          , bgcolor = bear_fvg_css))

    for bx in bullish_fvg_min
        if low < box.get_bottom(bx)
            box.delete(bx)
            box.delete(array.get(bullish_fvg_max, array.indexof(bullish_fvg_min, bx)))
    
    for bx in bearish_fvg_max
        if high > box.get_top(bx)
            box.delete(bx)
            box.delete(array.get(bearish_fvg_min, array.indexof(bearish_fvg_max, bx)))

//-----------------------------------------------------------------------------}
//Previous day/week high/lows
//-----------------------------------------------------------------------------{
//Daily high/low
[pdh, pdl] = request.security(syminfo.tickerid, 'D', hl()
  , lookahead = barmerge.lookahead_on)


//Display Daily
if show_pdhl
    define_previous_days_prices(pdh, pdl, 'D', pdhl_css)



//Premium and Discount Zones

var premium = box.new(na, na, na, na
  , bgcolor = color.new(premium_css, 80)
  , border_color = na)

var premium_lbl = label.new(na, na
  , text = supply_lbl_txt
  , color = TRANSP_COLOR
  , textcolor = #e43e3ee5
  , style = label.style_label_down
  , size = size.normal)

var discount = box.new(na, na, na, na
  , bgcolor = color.new(discount_css, 80)
  , border_color = na)

var discount_lbl = label.new(na, na
  , text = demand_lbl_txt
  , color = TRANSP_COLOR
  , textcolor = #13b667
  , style = label.style_label_up
  , size = size.normal)

//Show Premium and Discount Areas
if barstate.islast and show_sd
    avg = math.avg(trail_up, trail_dn)

    box.set_lefttop(premium, math.max(top_x, btm_x), trail_up)
    box.set_rightbottom(premium, n, .95 * trail_up + .05 * trail_dn)

    label.set_xy(premium_lbl, int(math.avg(math.max(top_x, btm_x), n)), trail_up)
    
    box.set_lefttop(discount, math.max(top_x, btm_x), .95 * trail_dn + .05 * trail_up)
    box.set_rightbottom(discount, n, trail_dn)
    label.set_xy(discount_lbl, int(math.avg(math.max(top_x, btm_x), n)), trail_dn)

//-----------------------------------------------------------------------------}
//Trend Definition
//-----------------------------------------------------------------------------{
var color trend_css = na



if style == 'Colored'
    trend_css := itrend == 1 ? bull_css : bear_css
else if style == 'Monochrome'
    trend_css := itrend == 1 ? #b2b5be : #5d606b



//-----------------------------------------------------------------------------}
// Definition of Possible Alerts
//-----------------------------------------------------------------------------{

alertcondition(bull_bos_alert, 'Bullish BOS', 'Quebra de Estrutura Bullish')
alertcondition(bull_choch_alert, 'Bullish CHoCH', 'Bullish CHoCH')

alertcondition(bear_bos_alert, 'Bearish BOS', 'Quebra de Estrutura Bearish')
alertcondition(bear_choch_alert, 'Bearish CHoCH', 'Bearish CHoCH')